package com.panopset.sf;

import static com.panopset.Util.log;
import static com.panopset.Util.x;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.TransferHandler;

import com.panopset.Util;
import com.panopset.compat.RezIO;
import com.panopset.java.Version;

/**
 * Persistent titled file selection field.
 *
 * @author Karl Dinwiddie
 *
 */
public final class TitledFileSelection {

    /**
     * Titled text area.
     */
    private final JTextField tta;

    private final ComponentFactory cf;

    /**
     * dropper.
     */
    private final JTextField dropper;

    /**
     * Panel.
     */
    private final JPanel p;

    /**
     * File dialog selection type. DIRECTORIES_ONLY or FILES_ONLY.
     */
    private final int fdst;

    /**
     * File dialog selection type.
     */
    private final int fddt;

    /**
     * @param w
     *            Windoc.
     * @param title
     *            Title name.
     * @param tip
     *            Tool tip text.
     * @param selectionType
     *            JFileChooser selection type, DIRECTORIES_ONLY or FILES_ONLY.
     * @param dialogType
     *            JFileChooser dialog type, OPEN_DIALOG or SAVE_DIALOG.
     * @param key
     *            Persistent store key. If the key is empty, a key will be
     *            generated based on the stack trace. If the key is null, there
     *            will be no registration.
     */
    public TitledFileSelection(final Windoc w, final String title,
            final String tip, final int selectionType, final int dialogType,
            final String key) {
    	cf = w.cf;
        if (!(selectionType == JFileChooser.DIRECTORIES_ONLY

        || selectionType == JFileChooser.FILES_ONLY)) {
            throw new RuntimeException(
                    "Must be DIRECTORIES_ONLY or FILES_ONLY.");
        }
        if (!(dialogType == JFileChooser.OPEN_DIALOG

        || dialogType == JFileChooser.SAVE_DIALOG)) {
            throw new RuntimeException("Must be OPEN_DIALOG or SAVE_DIALOG.");
        }
        fdst = selectionType;
        fddt = dialogType;
        tta = cf.createKeyedTextField(w, key);
        dropper = cf.createTextField(w, 2, tip, ">>", null);
        dropper.setEditable(false);
        dropper.setToolTipText(x("Drag 'n drop file here."));
        dropper.setBackground(Color.CYAN);
        dropper.setDragEnabled(true);
        dropper.setTransferHandler(new FileDropHandler());
        p = cf.createTitledPanel(new GridBagLayout(), title, "Select file.");

        final GridBagConstraints gbc = new GridBagConstraints();

        JButton btn = new JButton(Util.x("Browse"));
        btn.setMnemonic(KeyEvent.VK_B);
        btn.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                browse();
            }
        });
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 0;
        p.add(btn, gbc);
        gbc.gridx++;
        p.add(dropper, gbc);
        gbc.gridx++;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        p.add(tta, gbc);
    }

    /**
     * Browse for a file.
     */
    private void browse() {
        File f = null;
        JFileChooser chooser = new JFileChooser();
        chooser.setSelectedFile(getFile());
        chooser.setFileSelectionMode(fdst);
        chooser.setDialogTitle("Select");
        chooser.setDialogType(fddt);
        if (chooser.showOpenDialog(new JFrame())

        == JFileChooser.APPROVE_OPTION) {
            f = chooser.getSelectedFile();
        }
        if (f != null) {
            setFile(f);
        }
    }

    /**
     * @return File represented by text.
     */
    public File getFile() {
        return new File(tta.getText());
    }

    /**
     *
     * @param file
     *            File.
     */
    public void setFile(final File file) {
        if (file == null) {
            tta.setText("");
        } else {
            tta.setText(RezIO.getCanonicalPath(file));
        }
    }

    /**
     * @return Panel.
     */
    public JPanel getPanel() {
        return p;
    }

    /**
     * File drop handler.
     *
     * Reference:
     *
     * http://weblogs.java.net/blog/shan_man/archive/2006/09/toplevel_drop_w.
     * html
     *
     */
    final class FileDropHandler extends TransferHandler {

        /**
         * Can import.
         *
         * @param supp
         *            Transfer support.
         * @return True if the type of drag and drop is a list of files.
         */
        public boolean canImport(final TransferSupport supp) {
            /* for the demo, we'll only support drops (not clipboard paste) */
            if (!supp.isDrop()) {
                return false;
            }

            /* return true if and only if the drop contains a list of files */
            return supp.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
        }

        /**
         * Import data.
         *
         * @param supp
         *            Transfer support.
         * @return True if successful.
         */
        public boolean importData(final TransferSupport supp) {
            if (!canImport(supp)) {
                return false;
            }

            /* fetch the Transferable */
            Transferable t = supp.getTransferable();

            try {
                Object data = t.getTransferData(DataFlavor.javaFileListFlavor);
                if (!(data instanceof java.util.List<?>)) {
                    return false;
                }
                java.util.List<?> objList = (java.util.List<?>) data;
                for (Object o : objList) {
                    if (o instanceof File) {
                        File file = (File) o;
                        TitledFileSelection.this.setFile(file);
                        return true;
                    }
                }
            } catch (Exception e) {
                log(e);
            }

            return false;
        }

        /**
         * Serial version id.
         */
        private static final long serialVersionUID = Version.UNI_VERSION;
    }
}
